﻿using System;
using NUnit.Framework;
using ValidationFramework.Specifications;

namespace ValidationFramework.Specifications.Tests
{
	public class IsRequiredSpecTests
	{
		[TestFixture]
		public class Construction
		{
			[Test]
			public void Should_Default_InitialValue_To_Default_Of_Generic_Type()
			{
				var validator = new IsRequiredSpec<bool>();

				Assert.AreEqual(validator.InitialValue, default(bool));
			}

			[Test]
			public void Should_Set_HasInitialValue_To_True_When_Given_An_InitialValue()
			{
				var validator = new IsRequiredSpec<object>("SomeInitialValue");
				Assert.IsTrue(validator.HasInitialValue);
			}

			[Test]
			[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: initialValue")]
			public void Should_Throw_Exception_When_Given_Null_Initial_Value()
			{
				new IsRequiredSpec<object>(null);
			}
		}

		[TestFixture]
		public class Validate
		{
			[Test]
			public void Validate_NonNullAndNonInitialValue_ReturnTrue()
			{
				var validator = new IsRequiredSpec<string>("SomeInitialValue");

				Assert.IsTrue(validator.IsSatisfiedBy("SomeOtherValue"));
			}

			[Test]
			public void Validate_MiscBoolValues_ShouldReturnExpectedResult()
			{
				var validator = new IsRequiredSpec<bool>();

				Assert.IsTrue(validator.IsSatisfiedBy(false));
				Assert.IsTrue(validator.IsSatisfiedBy(true));
				Assert.IsFalse(validator.IsSatisfiedBy(null));

				var validator2 = new IsRequiredSpec<bool>(true);
				Assert.IsTrue(validator2.IsSatisfiedBy(false));
				Assert.IsFalse(validator2.IsSatisfiedBy(true));
				Assert.IsFalse(validator2.IsSatisfiedBy(null));

				var validator3 = new IsRequiredSpec<bool>(false);
				Assert.IsFalse(validator3.IsSatisfiedBy(false));
				Assert.IsTrue(validator3.IsSatisfiedBy(true));
				Assert.IsFalse(validator3.IsSatisfiedBy(null));
			}
			[Test]
			public void Validate_MiscIntValues_ShouldReturnExpectedResult()
			{
				var validator = new IsRequiredSpec<int>();

				Assert.IsTrue(validator.IsSatisfiedBy(0));
				Assert.IsTrue(validator.IsSatisfiedBy(5));
				Assert.IsFalse(validator.IsSatisfiedBy(null));

				var validator2 = new IsRequiredSpec<int>(0);
				Assert.IsFalse(validator2.IsSatisfiedBy(0));
				Assert.IsFalse(validator2.IsSatisfiedBy(null));
				Assert.IsTrue(validator2.IsSatisfiedBy(5));

				var validator3 = new IsRequiredSpec<int>(10);
				Assert.IsFalse(validator3.IsSatisfiedBy(10));
				Assert.IsFalse(validator3.IsSatisfiedBy(null));
				Assert.IsTrue(validator3.IsSatisfiedBy(5));
			}

			[Test]
			public void Validate_NullValue_ReturnFalse()
			{
				var validator = new IsRequiredSpec<object>();

				Assert.IsFalse(validator.IsSatisfiedBy(null));
			}

			[Test]
			public void Validate_NoInitialValueAndGivenDefault_ReturnTrue()
			{
				var validator = new IsRequiredSpec<bool>();

				Assert.IsTrue(validator.IsSatisfiedBy(default(bool)));
			}

			[Test]
			public void Validate_InitialValue_ReturnFalse()
			{
				var validator = new IsRequiredSpec<string>("SomeInitialValue");

				Assert.IsFalse(validator.IsSatisfiedBy("SomeInitialValue"));
			}

			[Test]
			public void Validate_EmptyString_ReturnFalse()
			{
				// arrange
				var validator = new IsRequiredSpec<string>();

				// assert
				Assert.IsFalse(validator.IsSatisfiedBy(""));
			}
		}

        [TestFixture]
        public class Equivalent
        {
            [Test]
            public void Should_Not_Be_Equivalent_If_Different_Generic_Types()
            {
                var validator1 = new IsRequiredSpec<bool>();
                var validator2 = new IsRequiredSpec<string>();

                Assert.IsFalse(validator1.IsEquivalentTo(validator2));
            }

            [Test]
            public void Should_Not_Be_Equivalent_If_Different_InitialValues()
            {
                var validator1 = new IsRequiredSpec<string>("Init1");
                var validator2 = new IsRequiredSpec<string>("Init2");

                Assert.IsFalse(validator1.IsEquivalentTo(validator2));
            }

            [Test]
            public void Should_Not_Be_Equivalent_If_Different_InitialValues_Null_Value()
            {
                var validator1 = new IsRequiredSpec<int>();
                var validator2 = new IsRequiredSpec<int>(0);

                Assert.IsFalse(validator1.IsEquivalentTo(validator2));
            }

            [Test]
            public void Should_Not_Be_Equivalent_If_Different_InitialValues_Null_Reference()
            {
                var validator1 = new IsRequiredSpec<DateTime>();
                var validator2 = new IsRequiredSpec<DateTime>(DateTime.Now);

                Assert.IsFalse(validator1.IsEquivalentTo(validator2));
            }

            [Test]
            public void Should_Be_Equivalent_With_Same_Generic_Type_And_Default_Constructors()
            {
                var validator1 = new IsRequiredSpec<string>();
                var validator2 = new IsRequiredSpec<string>();

                Assert.IsTrue(validator1.IsEquivalentTo(validator2));
            }
        }
	}
}
